#include "types.h"
#include "stat.h"
#include "user.h"
#include "fs.h"
#include "fcntl.h"
int mutex1;
int n = 6;
int atz = 5;
//this tests first creates two threads which prints their proc id and thread id three times each, the main thread than fork a new proc
//this proc create a new thread which calculate fibbonaci, and then this thread forks a new process which create a new thread that calculate atzerert. all the threads that calculate stuff returns the value in thread_exit and the threads that created them collect this value in join, and then prints the value.
void * print1 (){
	//for(;;){
	binary_sem_down(mutex1);
	printf(1,"thread from proc %d with id %d\n",thread_getProcId(),thread_getid());
	printf(1,"thread from proc %d with id %d\n",thread_getProcId(),thread_getid());
	printf(1,"thread from proc %d with id %d\n",thread_getProcId(),thread_getid());
	printf(1,"\n");
	binary_sem_up(mutex1);
	//if (fork == 0){
	//	thread_create(print2,malloc(1000),1000);
	//}
//	}
	thread_exit(0);
	return 0;
}

void * print2 (){
	int i;
	for(i=0;i<30;i++){
	binary_sem_down(mutex1);
	printf(1,"thread from proc %d with id %d\n",thread_getProcId(),thread_getid());
	printf(1,"thread from proc %d with id %d\n",thread_getProcId(),thread_getid());
	printf(1,"thread from proc %d with id %d\n",thread_getProcId(),thread_getid());
	printf(1,"\n");
	binary_sem_up(mutex1);
	//if (fork == 0){
	//	thread_create(print2,malloc(1000),1000);
	//}
	}
	thread_exit(0);
	return 0;
}

void * atzeret(){
	int i, ans =1;
	for ( i =2; i <= atz;i++){
		ans = ans *i;
	}
	thread_exit(&ans);
	return 0;
}

void * fibbonaci(){
	int i,tmp,t;
	int * res = malloc(4);
	int prev = 0;
	int curr = 1;
	for(i=1;i<n;i++){
		tmp=prev+curr;
		prev=curr;
		curr=tmp;
	}
	//printf(1,"fibbonaci = %d\n",curr);
	if (fork() ==0){
		printf(1,"proc %d has been created\n",getpid());
		t = thread_create(atzeret,malloc(1000),1000);
		binary_sem_down(mutex1);
		printf(1,"proc %d has created a thread %d to calculate !\n",getpid(),t);
		binary_sem_up(mutex1);
		thread_join(t,(void **) &res);
		binary_sem_down(mutex1);
		printf(1,"thread %d from proc %d has exited and returned result - %d for %d!\n",thread_getid(),thread_getProcId(),*res,atz);
		binary_sem_up(mutex1);
		thread_exit(0);
	}
	thread_exit(&curr);
	return 0;
					
}

int
main(int argc, char *argv[]){
	int i, j;
	//int* v;
	int *val = malloc(4);
	mutex1 = binary_sem_create();
	binary_sem_down(mutex1);
	printf(1,"proc number %d has started\n",thread_getProcId());
	binary_sem_up(mutex1);
	for (i=0; i< 2;i++){
		thread_create(print1,malloc(1000),1000);
	}
	
	if (fork() == 0){
		binary_sem_down(mutex1);
		printf(1,"proc number %d has started\n",thread_getProcId());
		binary_sem_up(mutex1);
		
		 j = thread_create(fibbonaci,malloc(1000),1000);
		//printf(1,"i got the result %d\n",*val);
		thread_join(j,(void**)&val);
		binary_sem_down(mutex1);
		printf(1,"proc %d got the result %d from fibbonaci with n = %d \n",getpid(),*val, n);
		binary_sem_up(mutex1);
		//wait();
		exit();
	}
	else {wait();thread_exit(0);}
	return 0;
}